#ifndef __OJ_USER_HPP__
#define __OJ_USER_HPP__
// 用户管理模块
#include <string>
#include <unordered_map>
#include "./mysql-connect/include/mysql.h"// 引用c-mysql-connect
#include "../common/log.hpp"

namespace ns_user
{
    using namespace ns_log;

    // 用户模块 先将数据库中存在的所有用户缓存到内存中来，这样每次就不需要访问数据库了
    struct UserObject
    {
        std::string id;  // 用户账号
        std::string password;  // 用户密码
        bool root = false;  // 用户管理权限 默认不是
    };

    const std::string oj_table_name = "oj_user";
    const std::string oj_host = "47.94.211.237";
    const std::string oj_user = "lyl";
    const std::string oj_password = "Lyl123456.";
    const std::string oj_db = "oj";
    const unsigned int oj_port = 3306;

    class User
    {
    public:
        std::unordered_map<std::string, std::string> _sessions;  // 存储会话数据的哈希表

        User()
        {}
        ~User()
        {}

        bool IsAdmin(const std::string& session_id) 
        {
            auto it = _sessions.find(session_id);
            if (it != _sessions.end()) {
                MYSQL_RES* res;
                std::string sql = "SELECT root FROM oj_user WHERE id='" + it->second + "'";
                if (QueryMySqlResult(sql, res) == 0) {
                    MYSQL_ROW row = mysql_fetch_row(res);
                    return row && atoi(row[0]) == 1;
                }
            }
            return false;
        }
        
        // 1 数据库连接失败
        // 2 执行结果报错 -注意select 查找不到不会报错
        int QueryMySqlResult(const std::string& sql, MYSQL_RES*& res)
        {
            // c连接mysql库，创建mysql对象-初始化mysql句柄
            MYSQL* oj_client = mysql_init(nullptr);
            // 连接数据库，连接失败返回nullptr
            if (nullptr == mysql_real_connect(oj_client, oj_host.c_str(), oj_user.c_str(), oj_password.c_str(), oj_db.c_str(), oj_port, nullptr, 0))
            {
                // 表示连接数据库失败
                LOG(FATAL) << "数据库连接失败！请尽快联系数据库管理员....." << "\n";
                return 1;
            }
            // 连接成功后先执行编码格式
            mysql_set_character_set(oj_client, "utf8");

            // 连接成功后执行语句
            int result = mysql_query(oj_client, sql.c_str());
            if (result != 0)
            {
                // 执行失败 sql语句的错误
                // LOG(WARING) << "sql语句存在错误：" << sql << "\n";
                return 2;
            }
            // 执行成功，提取数据
            res = mysql_store_result(oj_client);
            // 上层解析数据
            return 0;
        }

        // 0-查找成功，存在此用户
        // 1-内部错误
        // 2-用户名错误或不存在
        // 3-密码错误
        // 4-权限错误 测试
        int FindUser(const std::string& user_name, const std::string& password)
        {
    	    MYSQL_RES* res1 = nullptr;
    	    if (user_name.empty()) return 2;  // 用户名为空，返回 2

    	    std::string sql = "SELECT * FROM oj_user WHERE id='" + user_name + "';";
    	    if (0 != QueryMySqlResult(sql, res1)) return 1;  // 查询失败

    	    MYSQL_ROW line1 = mysql_fetch_row(res1);
    	    mysql_free_result(res1);  // 释放 res1，避免影响下一个查询

    	    if (line1 == nullptr){
                return 2;  // 用户不存在
        	}

    	    MYSQL_RES* res2 = nullptr;
    	    sql = "SELECT * FROM oj_user WHERE id='" + user_name + "' AND password=SHA2('" + password + "', 256);";
    	    if (0 != QueryMySqlResult(sql, res2)) return 3;  // 查询失败

    	    MYSQL_ROW line2 = mysql_fetch_row(res2);
    	    mysql_free_result(res2);  // 释放 res2，防止 MySQL 连接问题

    	    if (line2 == nullptr){
        	return 3;  // 密码错误
    		}  

    	    return 0;  // 登录成功
	    }


        // 1 内部错误
        // 2 用户名为空或者已经存在
        // 3 密码格式错误
        int RegisterUser(const std::string& user_name, const std::string& password)
        {
    	    MYSQL_RES* res = nullptr;
            if (user_name.empty()) return 2;  // 用户名为空，返回 2

    	    std::string sql = "SELECT * FROM oj_user WHERE id='" + user_name + "';";
    	    if (0 != QueryMySqlResult(sql, res)) return 1;  // 查询失败

            MYSQL_ROW line = mysql_fetch_row(res);
            mysql_free_result(res);  // 释放 res，防止内存泄漏

            if (line != nullptr){
                return 2;  // 用户名已存在
            }

    // **使用 SHA2(256) 存储密码**
    	    MYSQL* oj_client = mysql_init(nullptr);
    	    if (nullptr == mysql_real_connect(oj_client, oj_host.c_str(), oj_user.c_str(), oj_password.c_str(), oj_db.c_str(), oj_port, nullptr, 0))
            {
        	LOG(FATAL) << "数据库连接失败！\n";
        	return 1;
    	    }
            mysql_set_character_set(oj_client, "utf8");

    	    sql = "INSERT INTO oj_user(id, password, root) VALUES('" + user_name + "', SHA2('" + password + "', 256), 0);";
    	    int result = mysql_query(oj_client, sql.c_str());

    	    mysql_close(oj_client);  // 关闭数据库连接，防止泄漏

    	    if (result != 0) return 3;  // 插入失败

    	    return 0;  // 注册成功
	    }

        // 修改密码
        bool ChangePassWord(const std::string& user_name, const std::string& new_password)
        {
    // 1. 确保 `user_name` 不为空
    	    if (user_name.empty() || new_password.empty()) return false;

    // 2. 连接数据库
    	    MYSQL* oj_client = mysql_init(nullptr);
    	    if (nullptr == mysql_real_connect(oj_client, oj_host.c_str(), oj_user.c_str(), oj_password.c_str(), oj_db.c_str(), oj_port, nullptr, 0))
    	    {
        	LOG(FATAL) << "数据库连接失败！请尽快联系数据库管理员....." << "\n";
        	return false;
    	    }
    	    mysql_set_character_set(oj_client, "utf8");

    // 3. 使用 `SHA2()` 计算新密码，并更新数据库
    	    std::string sql = "UPDATE oj_user SET password = SHA2('" + new_password + "', 256) WHERE id = '" + user_name + "';";

    	    int result = mysql_query(oj_client, sql.c_str());  // 直接执行 `UPDATE`
    	    mysql_close(oj_client);  // 关闭数据库连接

    	    return (result == 0);  // `result == 0` 表示 `UPDATE` 成功
    	}

	// 生成一个随机的会话 ID
        std::string GenerateSessionId() {
            static const char alphanum[] =
                "0123456789"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                "abcdefghijklmnopqrstuvwxyz";
            
            const int id_length = 10;
            std::string session_id;
            for (int i = 0; i < id_length; ++i) {
                session_id += alphanum[rand() % (sizeof(alphanum) - 1)];
            }
            session_id += FileUtil::UniqueFileName();
            return session_id;
        }

        // 根据会话ID查找用户信息
        bool FindCookidUser(const std::string& session_id)
        {
            auto it = _sessions.find(session_id);
            return it != _sessions.end();
        }


	    std::string GetUsernameBySession(const std::string& session_id) 
        {
            auto it = _sessions.find(session_id);
            return (it != _sessions.end()) ? it->second : "";
        }



	    bool IsRoot(const std::string& username) 
        {
            MYSQL_RES* res = nullptr;
            std::string sql = "SELECT root FROM oj_user WHERE id='" + username + "';";
            if (QueryMySqlResult(sql, res) != 0) return false;
            MYSQL_ROW row = mysql_fetch_row(res);
            bool is_root = (row != nullptr && row[0][0] == '1'); 
	        mysql_free_result(res);
            return is_root;
        }

        
    };
}
#endif
